var ta;

var blockedLines = new Array();
var allowedLine;

var cursorPosition = 0;

var updateTimeout = 5 * 1000;

var timer;

var ws;

var debugArea = null;

/* the filename */
var filename = null;

/* the username of the editor */
var username = null;

/* the file id of the file beeing edited */
var fileid = null;

/* the username of the owner of the file */
var owner = null;

var canWrite = null;

var line = 0;

var arrow = {
    left: 37, 
    up: 38, 
    right: 39, 
    down: 40,
    del: 46,
    newline: 13,
    backspace: 8
};

/**
 * Lines start from 0
 */
function getCurrentLine() {
    var cur = getCurrentCursorPos();
    var nrNL = 0;
    var txtCon = ta.value;

    for (var i = 0; i < cur; i++)
        if (txtCon[i] == "\n")
            nrNL++;

    return nrNL;
}

function getCurrentCursorPos() {
    // this is not supported in IE. might want to act profesional.
    cursorPosition = ta.selectionStart;
    return cursorPosition;
}

function getLineContent(line) {
    var txtCon = ta.value;
    var cur_line = 0
    var content = "";
    
    for(var i = 0; i < ta.textLength && cur_line != line; i++)
    {
        if (txtCon[i] == "\n")
            cur_line++;
    }

    for(; i < ta.textLength && txtCon[i]!="\n"; i++)
        content += txtCon[i];
    
    return content;
}

function getCursorOffsetInLine() {
    var txtCon = ta.value;
    var cursPos = getCurrentCursorPos();
    var offset = 0;
    
    for (var i = 0; i < cursPos; i++) {
        offset++;
        if (txtCon[i] == "\n")
            offset = 0;
    }
    
    return offset;
}

function setCursorOffsetInLine(l, curOffset) {
    var txtCon = ta.value;
    var limit = ta.textLength;
    var offset = 0;
    
    
    for (; l > 0 && offset < limit; offset++) {
        if (txtCon[offset] == "\n")
            l--;
    }
    
    ta.selectionStart = offset + curOffset;
    ta.selectionEnd = offset + curOffset;
}

function setROMode() {
    ta.setAttribute("readonly", "readonly");
}

function setRWMode (){
    ta.removeAttribute("readonly");
}

function getNrLines() {
    var nrNL = 0;
    var txtCon = ta.value;

    for (var i = 0; i < ta.textLength; i++)
        if (txtCon[i] == "\n")
            nrNL++;

    return nrNL;
}

function allowedToEdit(line) {
    return !(line in blockedLines);
}

// TODO vezi de ce nu merge
function mousePress(evt) {
    var curLine = getCurrentLine();
    
    if (curLine == line || evt)
        return;
    line = curLine;
    setROMode();
    getLineStatus(curLine);
    
}

function updateInfo() {
    if (timer.active) {
        clearTimeout(timer);
    }
    
    requestCont();
    requestUrs();
    
    timer = setTimeout("updateInfo()", updateTimeout);
    timer.active = true;
}

/**
 * In case we decide we need something else
 */
function sendMessage(msg) {
    ws.send(msg);
}

function sendRestoreVers(vers) {
    if (canWrite != "true")
        return;
    var msg = "RES_VERS F=" + fileid + " V=" + vers;
    sendMessage(msg);
}

function getBlocked() {
    var msg = "REQ_BLOCKED F="+fileid;
    sendMessage(msg);
}

function getLineStatus(line) {
    var msg = "REQ_LINE F="+fileid+" L="+line+" U="+username;
    sendMessage(msg);
}

function updateLine(line) {
    if (allowedLine != line)
        return;
    var msg = "UPD_LINE F="+fileid+" L="+line+" U="+username+" T=" + getLineContent(line);
    sendMessage(msg);
}

function updateText() {
    var msg = "UPD_TEXT F="+fileid+" C="+owner+" N="+filename;
    sendMessage(msg);
}

function updatePing() {
    var msg = "UPD_PING F="+fileid+" C="+owner+" N="+filename;
    sendMessage(msg);
}

function saveFile() {
    var msg = "SAVE_FILE F="+fileid;
    sendMessage(msg);
}

function newLine(l) {
    var msg = "NEW_LINE F="+fileid+" L="+l+ " O="+ getCursorOffsetInLine() +" U="+username;
    sendMessage(msg);
}

function sendBackspace(line) {
    var msg = "DEL_LINE F="+fileid+" L="+line+" U="+username;
    sendMessage(msg);
}

function requestCont() {
    var msg = "REQ_CONT F="+fileid+" U="+username;
    sendMessage(msg);
}

function requestUrs() {
    var msg = "QRY_USRS F=" + fileid;
    sendMessage(msg);
}

function logDebug(msg) {
    if (debugArea != null) {
        debugArea.value += msg + "\n";
        debugArea.scrollTop = 1000000;
    }
}

function handle_inf_text(msg) {
    /* INF_TXT F=fid T={<p>line...} */
    var req = msg.split('=');
    var fid = req[1].split(" ")[0];
    var lines = req[2].substring(1, req[2].length-1).split("<p>");
    
    if (fid != fileid) {
        logDebug("INF_TXT wrong fid " + fid);
        return;
    }
    var text = lines[1];
    for (i = 2; i < lines.length; i++) {
        elem = lines[i];
        text += elem + "\n";
    }
    ta.value = text;
    getLineStatus(line);
}

function handle_inf_blocked(msg) {
    /* INF_BLOCKED F=fid L=[lines,] */
    var params = msg.split(" ");
    var fid;
    var blocks;
    
    for (var i = 0; i < params.length; i++) {
        var elem = params[i];
        if (elem == "INF_BLOCKED")
            continue;
        if (elem.substring(0,2) == "F=") {
            fid = parseInt(elem.substring(2));
            continue;
        }
        if (elem.substring(0,3) == "L=[") {
            blocks = elem.substring(3,elem.length-1).split(',');
            continue;
        }
        logDebug("INF_BLOCKED param:" + elem);
    }
    if (fid != fileid) {
        logDebug("INF_BLOCKED wrong fid " + fid);
        return;
    }
    blockedLines = blocks;
}

function handle_inf_line(msg)
{
    /* INF_LINE F=fid L=l U=uname R=t/f */
    var response = msg.split(" ");
    var fid = response[1].split("=")[1];
    var l = response[2].split("=")[1];
    var u = response[3].split("=")[1];
    var r = response[4].split("=")[1];

    if (fid == fileid && u == username) {
        if (r == "t") {
            allowedLine = l;
            var curLine = getCurrentLine();
            if (l == curLine) {
                setRWMode();
            }
        }
    } else
        logDebug("Inconsistency between request and reply data");
}

function handle_err(msg) {
    /* ERR_NOFILE */
    if (msg.substring(0,10) == "ERR_NOFILE")
        updatePing();
    else
        logDebug("Unkown error" + msg);
}

function handle_inf_context(msg) {
    /* INF_CONT F=id U=UNAME L=l T={<p>line...} */
    var req = msg.split('=');
    var fid = req[1].split(" ")[0];
    var u = req[2].split(" ")[0];
    var l = req[3].split(" ")[0];
    var lines = req[4].substring(1, req[4].length-1).split("<p>");
    
    if (fid != fileid) {
        logDebug("INF_CONT wrong fid " + fid);
        return;
    }
    if (u != username) {
        logDebug("INF_CONT wrong username " + u);
        return;
    }
    
    var text = "";
    for (i = 1; i < lines.length; i++) {
        /*if(i == l) {
            text += getLineContent(l);
            allowedLine = l;
            continue;
        }*/
        elem = lines[i];
        text += elem + "\n";
    }
    var curOffset = getCursorOffsetInLine();
    ta.value = text;
    if (l != -1)
        setCursorOffsetInLine(l, curOffset);
    if(l != -1 && line == l+1) {
        setRWMode();
    }
}

function handle_inf_usrs(msg) {
    /* INF_USRS F=id L={uname:line,} */
    var req = msg.split('=');
    var fid = req[1].split(" ")[0];
    var usrList = req[2].substring(1, req[2].length-1).split(',');
    
    if (fid != fileid) {
        logDebug("INF_USRS wrong fid " + fid);
        return;
    }
    
    $("#usrTableBody").children().remove();
    
    for (var i = 0; i < usrList.length-1; i++) {
        var indx = usrList[i].indexOf(':', 0);
        var usr = usrList[i].substring(0, indx);
        var line = usrList[i].substring(indx+1);
        $("#usrTableBody").append($('<tr>').
        append($('<td>').append(usr)).append($('<td>').append(line)));
    }
}

function interpretMsg(msg) {
    if (msg.substring(0,11) == "INF_BLOCKED")
        handle_inf_blocked(msg);
    else if (msg.substring(0,8) == "INF_LINE")
        handle_inf_line(msg);
    else if (msg.substring(0,7) == "INF_TXT")
        handle_inf_text(msg);
    else if (msg.substring(0,4) == "ERR_")
        handle_err(msg);
    else if (msg.substring(0,8) == "INF_CONT")
        handle_inf_context(msg);
    else if (msg.substring(0, 8) == "INF_USRS")
        handle_inf_usrs(msg);
    else if (msg == "OK")
        ; // Do nothing for the moment. we might want to change this
    // something like SAVE_OK
    else
        logDebug(msg);
}

function keyPressed(e) {
    var keyCode = e.keyCode || e.which;
    var curLine = getCurrentLine();
    var curs;
    
    switch (keyCode) {
        case arrow.left:
            curs = getCurrentCursorPos()-1;
            if (curs > 0)
                if (ta.value[curs] == "\n")
                    curLine--;
            break;
        case arrow.up:
            if (curLine > 0)
                curLine--;
            break;
        case arrow.right:
            curs = getCurrentCursorPos();
            if (curs < ta.textLength)
                if (ta.value[curs] == "\n")
                    curLine++;
            break;
        case arrow.down:
            if (curLine < getNrLines())
                curLine++;
            break;
        case arrow.backspace:
            curs = getCurrentCursorPos()-1;
            if (curs > 0) {
                if (ta.value[curs] == "\n") {
                    sendBackspace(curLine);
                }
            }
            break;
        
        case arrow.newline:
            //curLine++;
            newLine(curLine);
            break;
    
        case arrow.del:
            curs = getCurrentCursorPos();
            if (curs < ta.textLength)
                if (ta.value[curs] == "\n") {
                    sendBackspace(curLine+1);
                    curLine++;
                }
            break;

        default:
    }
    
    if (curLine == line)
        return;
    /* Send the contents of the previous line. */
    line = curLine;
    setROMode();
    /* Ask for permision to edit this line. */
    getLineStatus(curLine);
}

function keyUp(e) {
    var keyCode = e.keyCode || e.which;
    var curLine = getCurrentLine();
    var curs;
    
    switch (keyCode) {
        case arrow.left:
            curs = getCurrentCursorPos()-1;
            if (curs > 0)
                if (ta.value[curs] == "\n")
                    curLine--;
            break;
        case arrow.up:
            if (curLine > 0)
                curLine--;
            break;
        case arrow.right:
            curs = getCurrentCursorPos();
            if (curs < ta.textLength)
                if (ta.value[curs] == "\n")
                    curLine++;
            break;
        case arrow.down:
            if (curLine < getNrLines())
                curLine++;
            break;
        //case arrow.backspace:
        //break;
        case arrow.newline:
            curLine++;
            break;
        case arrow.del:
            break;

        default:
            updateLine(curLine);
    }
    return;
    if (curLine == line)
        return;
    /* Send the contents of the previous line. */
    updateLine(line);
    line = curLine;
    setROMode();
    /* Ask for permision to edit this line. */
    getLineStatus(curLine);
}

$(document).ready( function() {
    debugArea = document.getElementById('debug');
    
    var loc = document.location.toString().replace('http:', 'ws:');
    loc = loc.substring(0, loc.indexOf('/', 5));
    loc += ":9998/webClient";
    
    ta = document.getElementById("textpad");
    setROMode();
    
    var info = document.getElementById("info");
    filename = info.getAttribute("file");
    owner = info.getAttribute("owner");
    username = info.getAttribute("username");
    fileid = info.getAttribute("file_id");
    canWrite = info.getAttribute("writer");
    
    if (canWrite == "true") {
        //ta.setAttribute("onKeyPress", "keyPressed()");
        //ta.setAttribute("onKeyUp", "keyPressed(event, false);");
        //ta.setAttribute("onClick", "keyPressed()");

        $("#textpad").keypress(function(evt) {
            keyPressed(evt, false);
        })
        //.click(function(evt) {
        //    keyPressed(evt, true);
        //})
        .keyup(function(evt) {
            keyUp(evt, false);
        });
    }
    
    timer = setTimeout("updateInfo()", updateTimeout);
    
    if ("WebSocket" in window) {
        ws = new WebSocket(loc);
    } else if ("MozWebSocket" in window) {
        ws = new MozWebSocket(loc);
    } else {
        document.write("Your browser doesn't support websockets.");
        return;
    }

    ws.onopen = function() {
        logDebug("Connection established.");
        updateText();
        requestUrs();
    }

    ws.onmessage = function(evt) {
        var data = evt.data;
        interpretMsg(data);
    }

    ws.onclose = function(event) {
        var logMessage = 'Closed (';
        if ((arguments.length == 1) && ('CloseEvent' in window) &&
            (event instanceof CloseEvent)) {
            logMessage += 'wasClean = ' + event.wasClean;
            // code and reason are present only for
            // draft-ietf-hybi-thewebsocketprotocol-06 and later
            if ('code' in event) {
                logMessage += ', code = ' + event.code;
            }
            if ('reason' in event) {
                logMessage += ', reason = ' + event.reason;
            }
        } else {
            logMessage += 'CloseEvent is not available';
        }
        logDebug(logMessage + ')');
    }
    
    ws.onerror = function () {
        logDebug("Error");
    }
    
    window.onunload = function() {
        if (ws)
            ws.close();
    }
})
